#pragma once

#include "AttributeHijack.h"
#include "../json/Json.h"

template<class T>
struct Reflect_trait {
};

#define REFLECT_BEGIN(ClassName) \
template<> \
struct Reflect_trait<ClassName> { \
    template<class F> \
    static constexpr void forEachAttribute(ClassName &object, F &&func) {
#define REFLECT_ATTRIBUTE(ClassName, AttributeName) \
        func(#AttributeName, HijackGenerate::hijackGet_##ClassName##_##AttributeName(object));
#define REFLECT_END() \
    } \
};

/**
  * @brief  将类注册为反射类
  * @note   最大支持20个类属性
  * @param  要注册的类和类属性
  */
#define REFLECT(ClassName, ...) \
HIJACK(ClassName,__VA_ARGS__) \
REFLECT_BEGIN(ClassName) \
REFLECT_PP_FOREACH(ClassName, __VA_ARGS__) \
REFLECT_END()

/**
  * @brief  将已注册的类序列化为Json类型
  * @note   如果类未注册将会报错无法通过编译
  * @param  要序列化的类实例
  * @retval Json类型
  */
template<class T>
json::Json jsonSerialize(T &object) {
    json::Json root;
    Reflect_trait<T>::forEachAttribute(object, [&](const char *key, auto value) {
        root[key] = value;
    });
    return root;
}

#define REFLECT_PP_FOREACH_1(f, o, _1) f(o,_1)
#define REFLECT_PP_FOREACH_2(f, o, _1, _2) f(o,_1)f(o,_2)
#define REFLECT_PP_FOREACH_3(f, o, _1, _2, _3) f(o,_1)f(o,_2)f(o,_3)
#define REFLECT_PP_FOREACH_4(f, o, _1, _2, _3, _4) f(o,_1)f(o,_2)f(o,_3)f(o,_4)
#define REFLECT_PP_FOREACH_5(f, o, _1, _2, _3, _4, _5) f(o,_1)f(o,_2)f(o,_3)f(o,_4)f(o,_5)
#define REFLECT_PP_FOREACH_6(f, o, _1, _2, _3, _4, _5, _6) f(o,_1)f(o,_2)f(o,_3)f(o,_4)f(o,_5)f(o,_6)
#define REFLECT_PP_FOREACH_7(f, o, _1, _2, _3, _4, _5, _6, _7) f(o,_1)f(o,_2)f(o,_3)f(o,_4)f(o,_5)f(o,_6)f(o,_7)
#define REFLECT_PP_FOREACH_8(f, o, _1, _2, _3, _4, _5, _6, _7, _8) f(o,_1)f(o,_2)f(o,_3)f(o,_4)f(o,_5)f(o,_6)f(o,_7)f(o,_8)
#define REFLECT_PP_FOREACH_9(f, o, _1, _2, _3, _4, _5, _6, _7, _8, _9) f(o,_1)f(o,_2)f(o,_3)f(o,_4)f(o,_5)f(o,_6)f(o,_7)f(o,_8)f(o,_9)
#define REFLECT_PP_FOREACH_10(f, o, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) f(o,_1)f(o,_2)f(o,_3)f(o,_4)f(o,_5)f(o,_6)f(o,_7)f(o,_8)f(o,_9)f(o,_10)
#define REFLECT_PP_FOREACH_11(f, o, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11) f(o,_1)f(o,_2)f(o,_3)f(o,_4)f(o,_5)f(o,_6)f(o,_7)f(o,_8)f(o,_9)f(o,_10)f(o,_11)
#define REFLECT_PP_FOREACH_12(f, o, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12) f(o,_1)f(o,_2)f(o,_3)f(o,_4)f(o,_5)f(o,_6)f(o,_7)f(o,_8)f(o,_9)f(o,_10)f(o,_11)f(o,_12)
#define REFLECT_PP_FOREACH_13(f, o, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13) f(o,_1)f(o,_2)f(o,_3)f(o,_4)f(o,_5)f(o,_6)f(o,_7)f(o,_8)f(o,_9)f(o,_10)f(o,_11)f(o,_12)f(o,_13)
#define REFLECT_PP_FOREACH_14(f, o, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14) f(o,_1)f(o,_2)f(o,_3)f(o,_4)f(o,_5)f(o,_6)f(o,_7)f(o,_8)f(o,_9)f(o,_10)f(o,_11)f(o,_12)f(o,_13)f(o,_14)
#define REFLECT_PP_FOREACH_15(f, o, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15) f(o,_1)f(o,_2)f(o,_3)f(o,_4)f(o,_5)f(o,_6)f(o,_7)f(o,_8)f(o,_9)f(o,_10)f(o,_11)f(o,_12)f(o,_13)f(o,_14)f(o,_15)
#define REFLECT_PP_FOREACH_16(f, o, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16) f(o,_1)f(o,_2)f(o,_3)f(o,_4)f(o,_5)f(o,_6)f(o,_7)f(o,_8)f(o,_9)f(o,_10)f(o,_11)f(o,_12)f(o,_13)f(o,_14)f(o,_15)f(o,_16)
#define REFLECT_PP_FOREACH_17(f, o, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17) f(o,_1)f(o,_2)f(o,_3)f(o,_4)f(o,_5)f(o,_6)f(o,_7)f(o,_8)f(o,_9)f(o,_10)f(o,_11)f(o,_12)f(o,_13)f(o,_14)f(o,_15)f(o,_16)f(o,_17)
#define REFLECT_PP_FOREACH_18(f, o, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18) f(o,_1)f(o,_2)f(o,_3)f(o,_4)f(o,_5)f(o,_6)f(o,_7)f(o,_8)f(o,_9)f(o,_10)f(o,_11)f(o,_12)f(o,_13)f(o,_14)f(o,_15)f(o,_16)f(o,_17)f(o,_18)
#define REFLECT_PP_FOREACH_19(f, o, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19) f(o,_1)f(o,_2)f(o,_3)f(o,_4)f(o,_5)f(o,_6)f(o,_7)f(o,_8)f(o,_9)f(o,_10)f(o,_11)f(o,_12)f(o,_13)f(o,_14)f(o,_15)f(o,_16)f(o,_17)f(o,_18)f(o,_19)
#define REFLECT_PP_FOREACH_20(f, o, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20) f(o,_1)f(o,_2)f(o,_3)f(o,_4)f(o,_5)f(o,_6)f(o,_7)f(o,_8)f(o,_9)f(o,_10)f(o,_11)f(o,_12)f(o,_13)f(o,_14)f(o,_15)f(o,_16)f(o,_17)f(o,_18)f(o,_19)f(o,_20)
#define REFLECT_PP_FOREACH(ClassName, ...) CONCAT(REFLECT_PP_FOREACH_,COUNT_ARGS(__VA_ARGS__)(REFLECT_ATTRIBUTE,ClassName,__VA_ARGS__))